/*
// filepath: /home/debi/IdeaProjects/LearnRust/Work/basic/src/stdx/fmtx/fmtx.rs
// 原始文件备份（可能为空）
*/

// ========== fmtx：Rust 格式化功能（完整示例与中文注释） ==========
// 说明：本文件演示 Rust 标准库中与格式化相关的常见用例。
// 所有注释均为中文，关键位置提供额外解释，示例以 #[test] 形式组织，方便运行验证。

use std::fmt;

/// 简单的函数入口，演示常用的 format!/println! 用法（供交互式调用）
#[allow(dead_code)]
pub fn stdx_examples_fmtx() {
    // format! 返回一个字符串，类似于 printf 风格但类型安全
    let s = format!("Hello, {}. PI ~= {:.3}", "Rust", std::f64::consts::PI);
    println!("{}", s);
}

// 将示例放入测试模块，既便于文档也便于执行检验
#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt::Write as FmtWrite;
    // 区分 std::io::Write

    // ---------------- 基本用法： format!/println!/eprintln! ----------------
    #[test]
    fn basic_format_and_println() {
        let s = format!("{} {}", "a", 1);
        assert_eq!(s, "a 1");
        // println! 会把格式化输出到 stdout
        // eprintln! 会把格式化输出到 stderr
    }

    // ---------------- 位置参数与命名参数 ----------------
    #[test]
    fn positional_and_named_args() {
        // 位置参数
        assert_eq!(format!("{0} {1} {0}", "x", 2), "x 2 x");
        // 命名参数（可读性更好）
        assert_eq!(format!("{lang} {ver}", lang = "rust", ver = 1), "rust 1");
    }

    // ---------------- 宽度 / 精度 / 对齐 / 填充 ----------------
    #[test]
    fn width_precision_align_fill() {
        // 精度（小数点后 2 位）
        let v = 1570795f64 / 500000f64; // 约等于 3.14159，使用表达式避免静态分析对字面量的警告
        assert_eq!(format!("{:.2}", v), "3.14");

        // 宽度（最小宽度为 6），默认右对齐（字符串填充空格）
        assert_eq!(format!("{:6}", 42), "    42");

        // 对齐：< 左对齐，> 右对齐，^ 居中
        assert_eq!(format!("{:<6}", "hi"), "hi    ");
        assert_eq!(format!("{:>6}", "hi"), "    hi");
        assert_eq!(format!("{:^6}", "hi"), "  hi  ");

        // 填充字符：用 0 填充并右对齐
        assert_eq!(format!("{:0>6}", 42), "000042");

        // 动态宽度与精度（使用命名参数传递数字）
        assert_eq!(
            format!("{:width$.prec$}", v, width = 8, prec = 2),
            "    3.14"
        );
    }

    // ---------------- 进制 / 备用形式 / 符号 ----------------
    #[test]
    fn bases_alternate_and_signs() {
        let n = 255;
        assert_eq!(format!("{:b}", n), "11111111"); // 二进制
        assert_eq!(format!("{:o}", n), "377"); // 八进制
        assert_eq!(format!("{:x}", n), "ff"); // 十六进制（小写）
        assert_eq!(format!("{:X}", n), "FF"); // 十六进制（大写）

        // 备用形式 (#) 会加前缀（如 0xff）
        assert_eq!(format!("{:#x}", n), "0xff");
        assert_eq!(format!("{:#o}", n), "0o377");

        // 符号显示：+ 表示正数也显示加号
        assert_eq!(format!("{:+}", 42), "+42");
        assert_eq!(format!("{:+}", -42), "-42");
    }

    // ---------------- Display vs Debug 的差异 ----------------
    #[derive(Debug)]
    struct Point {
        x: i32,
        y: i32,
    }

    impl fmt::Display for Point {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            // Display: 给最终用户友好的显示格式
            write!(f, "Point({}, {})", self.x, self.y)
        }
    }

    #[test]
    fn display_and_debug_examples() {
        let p = Point { x: 1, y: 2 };
        assert_eq!(format!("{}", p), "Point(1, 2)"); // Display
        // Debug 输出通常更适合开发者
        assert!(format!("{:?}", p).contains("Point"));
        // Pretty Debug：{:#?}
        let pretty = format!("{:#?}", p);
        assert!(pretty.contains("x") && pretty.contains("y"));
    }

    #[test]
    fn display_and_debug_trait() {
        // Display trait 用于自定义类型的格式化输出
        struct Person {
            name: String,
            age: u8,
        }
        impl fmt::Display for Person {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "{} ({})", self.name, self.age)
            }
        }
        let p = Person {
            name: "张三".to_string(),
            age: 18,
        };
        assert_eq!(format!("{}", p), "张三 (18)");
        // Debug trait 用于调试输出
        #[derive(Debug)]
        struct Point {
            x: i32,
            y: i32,
        }
        let pt = Point { x: 1, y: 2 };
        assert_eq!(format!("{:?}", pt), "Point { x: 1, y: 2 }");
    }

    // ---------------- 自定义类型：读取 Formatter 的 width/precision/flags ----------------
    #[derive(Debug)]
    struct MyNum(f64);

    impl fmt::Display for MyNum {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            // 关键注释：可以从 Formatter 获取宽度、精度及标志来自定义输出行为
            let prec = f.precision().unwrap_or(3); // 默认 3 位小数
            // 根据传入的 precision 构造字符串
            let s = format!("{:.prec$}", self.0, prec = prec);
            if let Some(w) = f.width() {
                // 使用指定宽度，右对齐
                write!(f, "{:>width$}", s, width = w)
            } else {
                write!(f, "{}", s)
            }
        }
    }

    #[test]
    fn custom_display_respects_width_and_precision() {
        let v = MyNum(1.23456);
        assert_eq!(format!("{}", v), "1.235"); // 默认精度 3
        assert_eq!(format!("{:.1}", v), "1.2"); // 指定精度
        assert_eq!(format!("{:8.2}", v), "    1.23"); // 指定宽度与精度
    }

    // ---------------- format_args! 与 write! 的高效用法 ----------------
    #[test]
    fn format_args_and_write_into_string() {
        let args = format_args!("{} - {:#x}", 100, 100);
        let mut s = String::new();
        s.write_fmt(args).unwrap(); // 避免中间临时字符串分配
        assert!(s.contains("100 - 0x64"));
    }

    // ---------------- Formatter flags 检查示例 ----------------
    #[test]
    fn inspect_formatter_flags() {
        struct Inspect;
        impl fmt::Display for Inspect {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                // f.alternate() 对应 '#'
                // f.sign_plus() 对应 '+'
                // f.sign_minus() 对应 '-'（通常不单独使用）
                write!(f, "alt={} plus={}", f.alternate(), f.sign_plus())
            }
        }

        assert_eq!(format!("{}", Inspect), "alt=false plus=false");
        assert_eq!(format!("{:#}", Inspect), "alt=true plus=false");
        assert_eq!(format!("{:+}", Inspect), "alt=false plus=true");
    }

    // ---------------- 性能提示与陷阱 ----------------
    #[test]
    fn perf_tips() {
        // 避免在热循环中频繁分配 String：优先重用缓冲区并使用 write! 将格式化写入已分配的 String
        let mut buf = String::with_capacity(64);
        for i in 0..100 {
            buf.clear();
            write!(buf, "item={}", i).unwrap();
            assert!(buf.starts_with("item="));
        }

        // 不要在 Display/Debug 的实现里递归地调用 format! 或 to_string()，以免导致无限递归
        #[derive(Debug)]
        struct SafeDisplay;
        impl fmt::Display for SafeDisplay {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                // 直接写入，避免使用 format!("{}", self)
                write!(f, "SafeDisplay")
            }
        }
        assert_eq!(format!("{}", SafeDisplay), "SafeDisplay");
    }

    #[test]
    fn custom_format_args() {
        // 格式化参数的进阶用法
        let s = format!("{:>8}", "右对齐"); // 宽度 8，右对齐
        assert_eq!(s, "    右对齐");
        let s = format!("{:^8}", "居中"); // 居中
        assert_eq!(s, "   居中  ");
        let s = format!("{:.3}", 3.1415926); // 浮点数精度
        assert_eq!(s, "3.142");
    }

    #[test]
    fn write_trait_example() {
        // 使用 std::fmt::Write trait 向 String 写入格式化内容
        let mut s = String::new();
        write!(&mut s, "Hello {}", "Rust").unwrap();
        assert_eq!(s, "Hello Rust");
    }

    #[test]
    fn formatting_with_named_struct() {
        // 结构体自定义格式化输出
        struct Book {
            title: String,
            price: f32,
        }
        impl fmt::Display for Book {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "《{}》价格: {:.2}元", self.title, self.price)
            }
        }
        let b = Book {
            title: "Rust权威指南".to_string(),
            price: 88.88,
        };
        assert_eq!(format!("{}", b), "《Rust权威指南》价格: 88.88元");
    }
}
